﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using FDFtpSync.Core;
using FDFtpSync.Entities;

namespace FDFtpSync.Utils
{
    /*
     * CreatedOn: 2018-05-23
     * CreatedBy: Jackie Lee(天宇遊龍)
     */
    /// <summary>
    /// 目录、文件处理
    /// </summary>
    public static class PathHelper
    {
        /// <summary>
        /// 获取指定目录信息
        /// </summary>
        /// <param name="path"></param>
        /// <param name="root">根目录，以'/'分隔</param>
        /// <param name="relativeRoot">相对于根相对目录，以'/'开始</param>
        /// <param name="result"></param>
        public static void GetPathInfos(string path, string root, string relativeRoot, List<TransFile> result, List<string> specifiedDirs = null)
        {
            var dirs = Directory.GetDirectories(path);
            var files = Directory.GetFiles(path);
            FileInfo fi;
            foreach (var dir in dirs)
            {
                if (!IsSpecifiedDir(dir, root, specifiedDirs))
                {
                    continue;
                }
                fi = new FileInfo(dir);
                result.Add(new TransFile
                {
                    Name = fi.Name,
                    CreatedTime = fi.CreationTime,
                    ModifiedTime = fi.LastWriteTime,
                    AccessedTime = fi.LastAccessTime,
                    RelativeRoot = relativeRoot,
                    Path = ReplacePath(root, fi.FullName),
                    Size = 0,
                    Type = PathType.Dir
                });
                GetPathInfos(dir, root, relativeRoot, result);
            }

            foreach (var file in files)
            {
                fi = new FileInfo(file);
                result.Add(new TransFile
                {
                    Name = fi.Name,
                    CreatedTime = fi.CreationTime,
                    ModifiedTime = fi.LastWriteTime,
                    AccessedTime = fi.LastAccessTime,
                    RelativeRoot = relativeRoot,
                    Path = ReplacePath(root, fi.FullName),
                    Size = fi.Length,
                    Type = PathType.File
                });
            }
        }

        public static bool IsSpecifiedDir(string path, string root, List<string> specifiedDirs)
        {
            if (specifiedDirs == null || specifiedDirs.Count == 0)
            {
                return true;
            }

            var res = ReplacePath(root, path);
            if (res.LastIndexOf('/') == 0) // 只有相对于根一级目录才较验
            {
                return specifiedDirs.Contains(res);
            }

            return true;
        }

        public static string FormatPath(string path)
        {
            return path.Replace("\\", "/");
        }

        private static string ReplacePath(string root, string path)
        {
            path = path.Replace("\\", "/").Replace(root, "");
            return path.IndexOf('/') == 0 ? path : $"/{path}";
        }

        public static void CheckDir(string path)
        {
            if (!Directory.Exists(path))
            {
                Directory.CreateDirectory(path);
            }
        }

        public static void ChangeFileInfo(PathType pathType, string fileName, DateTime createdTime, DateTime modifiedTime, DateTime accessTime)
        {
            FileSystemInfo fi;
            if (pathType == PathType.File)
                fi = new FileInfo(fileName);
            else
                fi = new DirectoryInfo(fileName);
            fi.CreationTime = createdTime;
            fi.LastWriteTime = modifiedTime;
            fi.LastAccessTime = accessTime;
        }

        /// <summary>
        /// 将当前文件信息修改成目标一样
        /// </summary>
        /// <param name="fileName">当前文件</param>
        /// <param name="targetFileName">目标文件</param>
        public static void ChangeFileInfoAs(string fileName, string targetFileName)
        {
            var fi = new FileInfo(targetFileName);
            ChangeFileInfo(PathType.File, fileName, fi.CreationTime, fi.LastWriteTime, fi.LastAccessTime);
        }

        public static long GetFileLength(string fileName)
        {
            if (!File.Exists(fileName))
            {
                return 0;
            }
            using (var fs = new FileStream(fileName, FileMode.Open))
            {
                return fs.Length;
            }
        }

        public static void CheckSyncFile(List<TransFile> serverFiles, string localPath)
        {
            localPath = FormatPath(localPath);
            var dirs = Directory.GetDirectories(localPath, ".", SearchOption.AllDirectories);
            var files = Directory.GetFiles(localPath, ".", SearchOption.AllDirectories);
            foreach (var dir in dirs)
            {
                if (serverFiles.Any(s => s.Type == PathType.Dir && s.Path == ReplacePath(localPath, dir)))
                {
                    continue;
                }
                TryDelete(dir, PathType.Dir);
            }
            foreach (var file in files)
            {
                if (serverFiles.Any(s => s.Type == PathType.File && s.Path == ReplacePath(localPath, file)))
                {
                    continue;
                }
                TryDelete(file, PathType.File);
            }
        }

        public static void TryDelete(string path, PathType pathType)
        {
            try
            {
                if (pathType == PathType.Dir)
                {
                    if (Directory.Exists(path))
                        Directory.Delete(path, true);
                }
                else
                {
                    if (File.Exists(path))
                        File.Delete(path);
                }
            }
            catch (Exception ex)
            {
                SyncContext.Current.Logger.Value.Error($"删除{pathType}异常", ex);
            }
        }

        public static bool HasChanged(TransFile transFile, string fileName)
        {
            if (!File.Exists(fileName))
            {
                return true;
            }
            var fi = new FileInfo(fileName);
            return fi.LastWriteTime != transFile.ModifiedTime || fi.CreationTime != transFile.CreatedTime;
        }
    }
}
